﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using KPIS.DBM;
using KPIS.GERP.GHRMS.MODEL;

namespace KPIS.GERP.GHRMS.DAL
{
	public class _AutoDBM
	{
	    public readonly IDBManager DbManager;

        public _AutoDBM()
        {
            DbManager = new DBManager(SystemInfo._DataProvider, SystemInfo._ConnectionString);
        }

        public _AutoDBM(ref IDBManager dbManager)
        {
            DbManager = dbManager;
        }

		public enum ScriptType
		{
			Select,
			Insert,
			Update,
			Delete
		};

		public string GenerateSqlScript(ScriptType scriptType,
		                              object model)
        {
            if (scriptType == ScriptType.Delete)
            {
                return GenerateSqlDelete(model);
            } 
            
            if (scriptType == ScriptType.Insert)
            {
                return GenerateSqlInsert(model);
            }

			return "";
		}

		private object CallMethod(object model, string methodName, Type[] typeArg, object[] param = null)
		{
			Type modelType = model.GetType();
			MethodInfo methodInfo = modelType.GetMethod(methodName, typeArg);
			if (param == null)
				return methodInfo.Invoke(model, new object[0]);

		    return methodInfo.Invoke(model, param);

		    /* 
			string fieldSequence = (string)CallMethod(model, "GetSequenceFieldName",
											  new[] { typeof(TableInfoBase.SpecialFieldType) },
											  new object[] { TableInfoBase.SpecialFieldType.PrimaryKey }); 
			 */
		}

		private string GetProp(object model, TableInfo.Field info)
		{
		    string a1 = Convert.ToString(info);
		    Type a2 = model.GetType();
		    PropertyInfo a3 = a2.GetProperty(a1);
		    var a4 = a3.GetValue(model, null);
			return (string)a4;
		} 

		private void DbmAssignParameter(object someObject)
		{
			Dictionary<string, string> fieldsValues = GetValuesOfObject(someObject, false);
			DbManager.CreateParameters(fieldsValues.Count);
			int i = 0;
			foreach (KeyValuePair<string, string> fieldValue in fieldsValues)
			{
				DbManager.AddParameters(i++, String.Format("@{0}", fieldValue.Key), fieldValue.Value);
			}
		}

		private string GenerateSqlDelete(object model)
		{
			string deleteStatus = SystemInfo._DeleteRecordStatus;

			string primaryKeyFieldName = GetProp(model, TableInfo.Field.PrimaryKey); 

			object primaryKeyValue =
				model.GetType().GetProperty(GetProp(model, TableInfo.Field.PrimaryKeyClass)).GetValue(model, null);

			string updateByFieldName = GetProp(model, TableInfo.Field.UpdateBy);

			object updateByValue =
				model.GetType().GetProperty(GetProp(model, TableInfo.Field.UpdateByClass)).GetValue(model, null);

			string updateWhenFieldName =GetProp(model, TableInfo.Field.UpdateWhen);

			object updateWhenValue =
				model.GetType().GetProperty(GetProp(model, TableInfo.Field.UpdateWhenClass)).GetValue(model, null);

			string recordStatusFieldName =GetProp(model, TableInfo.Field.RecordStatusField);

			object recordStatusValue = SystemInfo._DeleteRecordStatus;

			string tableName = GetProp(model, TableInfo.Field.TableName);


			return String.Format(@"
UPDATE {8} 
SET
/*updated_by*/ {0}= @{0} , 
/*updated_when*/ {2}= @{2}, 
/*record_status*/ {4}= @{4}
	
WHERE
/*health_check_seq*/ {6} = @{6};
",
			                     updateByFieldName,
								 updateByValue,
								 updateWhenFieldName,
								 updateWhenValue,
								 recordStatusFieldName,
								 recordStatusValue,
			                     primaryKeyFieldName,
								 primaryKeyValue,
								 tableName );

		}

        private string GenerateSqlInsert(object model)
        {
            string primaryKeyFieldName = GetProp(model, TableInfo.Field.PrimaryKey);
            string updateByFieldName = GetProp(model, TableInfo.Field.UpdateBy);
            string updateWhenFieldName = GetProp(model, TableInfo.Field.UpdateWhen);
            string recordStatusFieldName = GetProp(model, TableInfo.Field.RecordStatusField);
            string tableName = GetProp(model, TableInfo.Field.TableName);

            Dictionary<string, string> data = GetValuesOfObject(model, true);
            Dictionary<string, string> dataNonRecordStatus = GetNonRecordStatusFields(data
                                                                                      , updateByFieldName
                                                                                      , updateWhenFieldName
                                                                                      , recordStatusFieldName
                                                                                      , primaryKeyFieldName);
            Dictionary<string, string> dataRecordStatus =
                new Dictionary<string, string>
                    {
                        {updateWhenFieldName, data[updateWhenFieldName]}
                        ,{recordStatusFieldName, data[recordStatusFieldName]}
                        ,{primaryKeyFieldName, data[primaryKeyFieldName]}
                    };

            string fieldsList = "";
            foreach (string k in dataNonRecordStatus.Keys)
            {
                fieldsList += ", " + k + Environment.NewLine;
            }
            foreach (string k in dataRecordStatus.Keys)
            {
                fieldsList += ", " + k + Environment.NewLine;
            }
            fieldsList = fieldsList.Substring(2, fieldsList.Length - 3);

            string valuesList = "";
            foreach (string k in dataNonRecordStatus.Keys)
            {
                valuesList += ", @" + k + Environment.NewLine;
            }
            foreach (string k in dataRecordStatus.Keys)
            {
                valuesList += ", @" + k + Environment.NewLine;
            }
            valuesList = valuesList.Substring(2, valuesList.Length - 3);

            return String.Format(@"INSERT INTO {0}
                                    (
                                        {1}
                                    ) VALUES (
                                        {2}
                                    );"
                                 , tableName
                                 , fieldsList
                                 , valuesList);

        }

        public List<string> GetFieldsName(object model)
        {
            var result = new List<string>();
            var propertyInfos = model.GetType().GetProperties();

            foreach (PropertyInfo pInfo in propertyInfos)
            {
                if (Attribute.IsDefined(pInfo, typeof(FieldAttribute)))
                {
                    var fieldAttribute =
                            (FieldAttribute)Attribute.GetCustomAttribute(pInfo, typeof(FieldAttribute));

                    result.Add(fieldAttribute.FieldName);
                }
            }

            return null;
        }


        public Dictionary<string, string> GetNonRecordStatusFields(Dictionary<string, string> data
            , string updateByFieldName
            , string updateWhenFieldName
            , string recordStatusFieldName
            , string primaryKeyFieldName = null)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            foreach (KeyValuePair<string, string> each in data)
            {
                if (each.Key != updateByFieldName &&
                    each.Key != updateWhenFieldName &&
                    each.Key != recordStatusFieldName
                    )
                {
                    result.Add(each.Key, each.Value);
                }
            }

            return result;
        }

		public void UpdateParameter(object someObject)
		{
			Dictionary<string, string> fieldsValues = GetValuesOfObject(someObject, false);
			DbManager.CreateParameters(fieldsValues.Count);
			int i = 0;
			foreach (KeyValuePair<string, string> fieldValue in fieldsValues)
			{
				DbManager.AddParameters(i++, String.Format("@{0}", fieldValue.Key), fieldValue.Value);
			}
		}

        public Dictionary<string, string> GetValuesOfObject(object model, bool onlyField)
        {
            var result = new Dictionary<string, string>();
            var propertyInfos = model.GetType().GetProperties();

            var fieldsName = GetFieldsName(model);

            foreach (PropertyInfo pInfo in propertyInfos)
            {
                string propertyName = pInfo.Name; //gets the name of the property
                object propertyValue = pInfo.GetValue(model, null);

                if (!fieldsName.Contains(propertyName) && onlyField) continue;

                if (propertyValue == null)
                {
                    result.Add(propertyName, null);
                }
                else if (propertyValue is DateTime)
                {
                    try
                    {
                        Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
                        string resultStr = ((DateTime)propertyValue).ToString("yyyy-MM-dd HH:mm:ss");
                        result.Add(propertyName, resultStr);
                    }
                    catch
                    {
                        result.Add(propertyName, null);
                    }
                }
                else
                {
                    result.Add(propertyName, Convert.ToString(propertyValue));
                }
            }

            return result;
        }
	}
}
